#pragma once
#include <iostream>
#include <poll.h>
#include <unistd.h>
#include "Sock.hpp"
#include<string>
using namespace std;
static const int defaultfd = -1;
static const short defaultevents=0;
#define N 1024 //原代码是4096,centos系统；ubuntu上上限是1024
typedef struct pollfd Type;
class PollServer
{
public:
    PollServer(uint16_t port = 8888)
        : _port(port)
    {
    }

    void Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        _fdarray=new Type[N];
        for(int i=0;i<N;i++)
        {
            _fdarray[i].fd=defaultfd;
            _fdarray[i].events=defaultevents;
            _fdarray[i].revents=defaultevents;
        }

      
    }

    void HandleAccept()
    {
        //这里在进行Accept会不会被阻塞??不会的!
        string clientip;
        uint16_t port;
        int sock = _listensock.Accept(clientip, port);
        if (sock < 0)
        {
            return;
        }
        // 得到了对应的sock, 我们可不可以进行read/recv，读取sock？不能
        // 你怎么知道sock上有数据就绪了？不知道，所以我们需要将sock交给select，让select进行管理！
        LogMessage(Information, "[%s,%d],sock:%d", clientip.c_str(), port, sock);
       // 要让select 帮我们进行关心，只要把sock添加到fdarray_[]里面即可！
        int i;
        for (i = 0; i < N; i++)
        {
            if (_fdarray[i].fd== defaultfd)
            {
                break;
            }
        }
        if (i >= N)
        {
            LogMessage(Warning, "sock array have already full");
            //扩容...
        }
        else
        {
            _fdarray[i].fd = sock;
            _fdarray[i].events=POLLIN;
            _fdarray[i].revents=defaultevents;
        }
    }

    void HandleSelect()
    {
        for (int i = 0; i < N; i++)
        {
            if (_fdarray[i].fd == defaultfd)
            {
                continue;
            }

            //1.一个判断是否是listensock
            //2.判断是否已经就绪
            if (_fdarray[i].fd== _listensock.GetSock() &&_fdarray[i].revents==POLLIN)
            //需要判断是否是listensock的原因是如果不判断就会一直调用accept
            {
                HandleAccept();
            }
            else if (_fdarray[i].fd != _listensock.GetSock() && _fdarray[i].revents==POLLIN)
            {
                // 读
                int fd = _fdarray[i].fd;
                char buff[1024];
                int n = read(fd, buff, sizeof(buff) - 1);// 读取会被阻塞吗？不会
                if (n > 0)
                {
                    buff[n] = 0;
                    cout << "client echo:" << buff << endl;
                    string send_to = buff;
                    send_to+="[select server echo]";
                    cout<<send_to<<endl;
                    write(fd, send_to.c_str(), send_to.size());
                }
                else
                {
                    if (n == 0)
                    {
                        LogMessage(Information, "client want to end...");
                    }
                    else
                    {
                        LogMessage(Warning, "read error,errno:%d,string:%s", errno, strerror(errno));
                    }

                    close(fd); // 不能忘记，remember
                    _fdarray[i].fd= defaultfd;
                    _fdarray[i].events=defaultevents;
                    _fdarray[i].revents=defaultevents;
                }
            }
        }
    }

    void Start()
    {
        // 1. 这里我们能够直接获取新的链接吗？
        // 2. 最开始的时候，我们的服务器是没有太多的sock的，甚至只有一个sock！listensock
        // 3. 在网络中， 新连接到来被当做 读事件就绪！
        // listensock_.Accept(); 不能！

        _fdarray[0].fd=_listensock.GetSock();
        _fdarray[0].events=POLLIN;
        while (true)
        {
            int n =poll(_fdarray,N,-1);
            if (n == 0)
            {
                LogMessage(Information, "time is out...");
                continue;
            }
            else if (n < 0)
            {
                LogMessage(Warning, "poll is error,errno:%d,string:%s", errno, strerror(errno));
                sleep(1);
                continue;
            }
            else
            {
                // 有文件描述符可读
                LogMessage(Debug, "There is at  %d fd(s) has already", n);
                HandleSelect();
                DebugPrint();
                continue;
            }
        }
    }
    void DebugPrint()
    {
        std::cout << "fdarray[]: ";
        for (int i = 0; i < N; i++)
        {
            if (_fdarray[i].fd == defaultfd)
                continue;
            std::cout << _fdarray[i].fd << " ";
        }
        std::cout << "\n";
    }

private:
    Sock _listensock;
    uint16_t _port;
    Type * _fdarray;
};